﻿using MotorLibrary.DAL;
using MotorLibrary.Error;
using MotorLibrary.Repository;
using MotorLibrary.Repository.DTO;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;

namespace MotorLibrary.Service
{
    public class EjecucionService : IEjecucionService
    {
        private IEndpointService _endpointService;
        private IEjecucionRepository _ejecucionRepository;
        private IDescargadorFactory _descargadorFactory;
        private IVariableService _variableService;
        private IVariableEjecucionService _variableEjecucionService;

        public EjecucionService(
            IEndpointService endpointService, 
            IEjecucionRepository ejecucionRepository, 
            IDescargadorFactory descargadorFactory,
            IVariableService variableService,
            IVariableEjecucionService variableEjecucionService)
        {
            this._endpointService = endpointService;
            this._ejecucionRepository = ejecucionRepository;
            this._descargadorFactory = descargadorFactory;
            this._variableService = variableService;
            this._variableEjecucionService = variableEjecucionService;
        }

        private string ObtenRaizRepositorio()
        {
            return System.Configuration.ConfigurationManager.AppSettings["Repository"].ToString();
        }

        private string CalculaDestino(string uri, DateTime fechaEjecucion, long endpointID)
        {            
            string rutaDescarga = endpointID + "/" +
                fechaEjecucion.Year +
                fechaEjecucion.Month +
                fechaEjecucion.Day +
                fechaEjecucion.Hour +
                fechaEjecucion.Minute +
                fechaEjecucion.Second +
                fechaEjecucion.Millisecond + "-" +
                Path.GetFileName(uri);
            return rutaDescarga;
        }

        public EjecucionDTO Create(EjecucionDTO dto)
        {
            EjecucionDTO resultado;

            long idendpoint = dto.EndpointID;
            EndpointDTO dtoend = _endpointService.Read(idendpoint);
            if (dtoend == null)
                throw new NoEncontradaException(idendpoint, "No existe el endpoint especificado.");
            
            string uri = dtoend.Ruta;
            long type = dtoend.TipoID;
            
            DateTime fechaEjecucion = DateTime.Now;
            string rutaDescarga = CalculaDestino(uri, fechaEjecucion, idendpoint);
            string ficheroDestino = ObtenRaizRepositorio() + "/" + rutaDescarga;
            Directory.CreateDirectory(Path.GetDirectoryName(ficheroDestino));

            IDescargador descargador = _descargadorFactory.GetInstance(type);
            dto.Tamano = descargador.Descarga(uri, ficheroDestino);
            dto.FechaEjecucion = fechaEjecucion;
            dto.RutaDescarga = rutaDescarga;
            resultado = _ejecucionRepository.Create(dto);

            if (dtoend.Procesar)
            {
                JObject jObject = JObject.Parse(File.ReadAllText(ficheroDestino));
                IList<VariableDTO> variables = _variableService.FilterByEndpoint(idendpoint);

                foreach (VariableDTO variable in variables)
                {
                    VariableEjecucionDTO nuevaVarEjec = new VariableEjecucionDTO();
                    nuevaVarEjec.EjecucionID = resultado.ID;
                    nuevaVarEjec.VariableID = variable.ID;
                    var valorTmp = jObject[variable.Nombre];
                    if (valorTmp == null)
                        nuevaVarEjec.Valor = "";
                    else
                        nuevaVarEjec.Valor = valorTmp.ToString();
                    _variableEjecucionService.Create(nuevaVarEjec);
                }
            }

            return resultado;
        }

        public EjecucionDTO Read(long id)
        {
            return _ejecucionRepository.Read(id);
        }

        public IList<EjecucionDTO> List()
        {
            return _ejecucionRepository.List();
        }

        public IList<EjecucionDTO> FilterByEndpoint(long endpointID)
        {
            return _ejecucionRepository.Filter(ejecucion => ejecucion.EndpointID == endpointID);
        }
    }
}